package com.yyg.usecase.datastructure;

import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;

class LFUCache<K, V> {
    int capacity;
    Map<K, Node<K, V>> map;
    PriorityQueue<Node<K, V>> queue;

    public LFUCache(int capacity){
        this.capacity = capacity;
        this.map = new HashMap<>(capacity);
        queue = new PriorityQueue<>();
    }

    public V get(K key) {
        if(map.containsKey(key)) {
            Node<K, V> node = map.get(key);
            node.frequency++;
            node.timestamp++;
            queue.remove(node);
            queue.offer(node);
            return node.value;
        }
        return null;
    }

    public void put(K key, V value) {
        if(map.containsKey(key)) {
            Node<K, V> node = map.get(key);
            node.frequency++;
            node.timestamp++;
            node.value = value;
            queue.remove(node);
            queue.offer(node);
        }else {
            int size = map.size();
            if(size >= capacity) {
                Node<K, V> node = queue.poll();
                map.remove(node.key);
            }
            Node<K,V> newNode = new Node<>(key, value, 1,0);
            map.put(key, newNode);
            queue.offer(newNode);
        }
    }

    public void display(){
        for (Node<K, V> node : queue) {
            System.out.print(node.key + "=" + node.value + "(freq=" + node.frequency + ") ");
        }
        System.out.println();
    }

    class Node<K, V> implements Comparable<Node<K,V>>{
        K key;
        V value;
        long frequency;
        long timestamp;

        public Node(K key, V value, long frequeny, long timestamp) {
            this.key = key;
            this.value = value;
            this.frequency = frequeny;
            this.timestamp = timestamp;
        }

        @Override
        public int compareTo(Node<K, V> node) {
            return Long.compare(this.frequency, node.frequency);
        }
    }
}
